/* eslint-disable @typescript-eslint/indent */
import {
    ChangeDetectorRef, Component, ComponentFactoryResolver, ElementRef, Injector,
    NgZone, OnDestroy, OnInit, ViewChild
} from '@angular/core';

import { DesignerHost } from './service/designer-host';
import { BOTTOM_TAB_TYPE, LEFT_TAB_TYPE } from './entity/form-designer-entity';
import { MessagerService } from '@farris/ui-messager';
import { FrameProp } from './entity/frame-property-config';
import { ClassEditorComponent } from './panels/class-editor/class-editor.component';
import { BsModalService } from '@farris/ui-modal';
import { RowNode, TreeNode } from '@farris/ui-treetable';
import ResizeObserver from 'resize-observer-polyfill';
import { PropertyPanelComponent, ShowMode } from '@farris/ide-property-panel';
import { DomValidtionService } from './service/dom-validation.service';
import { DesignerMetadataService } from '../service/designer-metadata.service';
import { isEqual } from 'lodash-es';
import { AdaptOldFormService } from './service/adapt-old-form.service';
import { BuilderHTMLElement, IDesignerHost, FarrisDesignBaseComponent, DesignerBuilder } from '@farris/designer-element';
import {
    DomService, EventEditorService, DesignViewModelService, SchemaService, DesignerHostSettingService,
    StateMachineService, DataStatesService, RefreshFormService, FormBasicService, WebCmdService, FarrisMetadataService
} from '@farris/designer-services';
import {
    AllComponents, ControlService, FormPropertyChangeObject, ControlEventPropertyIDList,
    ControlPropertyChangedService, ControlCreatorService, SchemaDOMMapping, DgControl
} from '@farris/designer-ui';
import {
    DragResolveService, ControlBoxComponent, ControlTreeNodeType, ControlTreeNode,
    ControlTreeComponent, SchemaTreeComponent
} from '@farris/designer-devkit';

const DEFAULT_PROPERTY_PANEL_WIDTH = '300px';

@Component({
    selector: 'app-form-designer',
    templateUrl: './form-designer.component.html',
    styleUrls: ['./form-designer.component.css'],
    providers: [ControlPropertyChangedService,
    ]
})
export class FormDesignerComponent implements OnInit, OnDestroy {

    /** 可视化区域构造器 */
    public designBuilder: DesignerBuilder;

    /** 当前右侧显示的视图类型 */
    public bottomTabActive = BOTTOM_TAB_TYPE.formDesigner;

    /** 当前左侧显示的tab页 */
    public leftTabActive = LEFT_TAB_TYPE.controlTree;

    /** 页面控件实例集合 */
    public componentInstanceList: FarrisDesignBaseComponent[];

    /** 当前选中控件实例 */
    public focusedComponentInstance: any;

    /** 属性面板配置数据 */
    public propertyConfig = [];

    /** 属性面板绑定数据 */
    public propertyData: any;

    /** 当前选中的属性面板标签页ID */
    public selectedPropertyTabId: string;

    /** 当前在控件树上选中的视图模型id */
    public focusedViewModelId: string;

    /** 属性面板是否支持左右拖动 */
    public propertyPanelResizeable = true;

    /** 属性面板宽度 */
    public propertyPanelWidth: string = DEFAULT_PROPERTY_PANEL_WIDTH;

    /** 表单完整DOM结构 */
    get domJson() {
        return this.domService.getDomJson();
    }

    /** 代码编辑器绑定的字符串 */
    public monacoCode: string;

    /** 代码编辑器实例 */
    private monacoEditor: any;

    /** 控件树组件实例 */
    @ViewChild('controlTree') private controlTree: ControlTreeComponent;

    /** 控件工具箱实例 */
    @ViewChild('controlBox') private controlBox: ControlBoxComponent;

    /** 实体树组件实例 */
    @ViewChild('schemaTree') private schemaTree: SchemaTreeComponent;

    /** 样式编辑器组件实例 */
    @ViewChild(ClassEditorComponent) private classEditorComponent: ClassEditorComponent;

    @ViewChild(PropertyPanelComponent) private propertyPanelComponent: PropertyPanelComponent;

    private ro: ResizeObserver = null;

    private elRef: ElementRef = null;

    private _roTimer = null;

    private iFrameTabId: string;

    /** 代码编辑器内容发生变更 */
    private isMonacoEditorChanged = false;

    constructor(
        private domService: DomService,
        private schemaService: SchemaService,
        private dgVMService: DesignViewModelService,
        private controlService: ControlService,
        private stateMachineService: StateMachineService,
        private dataStatesService: DataStatesService,
        private modalService: BsModalService,
        private msgService: MessagerService,
        private componentFactoryResolver: ComponentFactoryResolver,
        private injector: Injector,
        private designerHostSettingService: DesignerHostSettingService,
        private controlPropertyChangedService: ControlPropertyChangedService,
        private ngZone: NgZone,
        private dragResolveService: DragResolveService,
        private controlCreatorService: ControlCreatorService,
        private refreshFormService: RefreshFormService,
        private formBasicService: FormBasicService,
        private webCmdService: WebCmdService,
        private eventEditorService: EventEditorService,
        private cd: ChangeDetectorRef,
    ) {

        this.elRef = this.injector.get(ElementRef);
        // this.iFrameTabId = gsp.ide.getParam('id');
    }

    ngOnInit() {
        // 监听外部刷新表单的事件
        this.refreshFormService.refreshFormDesigner.subscribe((targetComponentId) => {
            this.refreshFormAndTree(targetComponentId);
        });
        // 监听外部刷新实体树的事件
        this.refreshFormService.refreshSchamaTree.subscribe(() => {
            this.schemaTree.refreshTreeData();
        });
        // 监听外部刷新控件树的事件
        this.refreshFormService.refreshControlTree.subscribe(() => {
            this.controlTree.refreshControlTree();
        });
    }

    ngOnDestroy() {
        if (this.ro) {
            this.ro.unobserve(this.elRef.nativeElement);
            this.ro.disconnect();
            this.ro = null;
        }

        this.designBuilder = null;
        this.refreshFormService.refreshFormDesigner.unsubscribe();
        this.refreshFormService.refreshSchamaTree.unsubscribe();
        this.refreshFormService.refreshControlTree.unsubscribe();
    }

    render(dom: any) {

        // 保存DOM
        this.domService.setDomJson(dom,
            (path: string, newValue: any, previousValue: any) => this.domChangedCallback(path, newValue, previousValue));

        // 适配旧表单
        const adaptFormService = new AdaptOldFormService(this.injector);
        adaptFormService.adaptOldForm();

        // 事件编辑器集成
        this.webCmdService.checkCommands();

        // 组合ViewModel数据：schema field+VM changeset => dgViewModel
        this.dgVMService.assembleDesignViewModel();

        // 渲染页面
        this.createDesignBuilder(this.domJson);

        // 刷新实体树
        this.schemaTree.refreshTreeData();
    }

    private domChangedCallback(path: string, newValue: any, previousValue: any): void {
        // 不重复发送变更通知
        if (window.isFormMetadataChanged) {
            return;
        }
        // 当前处于变更挂起状态
        if (window.suspendChangesOnForm) {
            return;
        }
        // 排除的节点，仅用于设计时，用于不感知
        if (['module.actions'].includes(path)) {
            return;
        }
        // 部分属性是设计器控制显示状态的，无关运行时，可以不保存，所以不记录变更
        if (path && (path.includes('InDesignerView') || path.includes('currentViewShowType'))) {
            return;
        }

        // 新旧值相同，不记录变更
        if (newValue && previousValue) {
            if (isEqual(newValue, previousValue)) {
                return;
            }
        }

        // 通知IDE设计器变更
        // if (gsp && gsp.ide && gsp.ide.setDesignerStatus) {
        //     window.isFormMetadataChanged = true;

        //     gsp.ide.setDesignerStatus(this.iFrameTabId, true);
        //     // console.log('domChanged,path=', path);
        // }
    }

    private createDesignBuilder(domJson: any) {
        // 画布渲染过程中，可能会在控件上补充属性，这种变更用户不感知，所以不需要通知IDE框架
        window.suspendChangesOnForm = true;

        const elements = document.getElementsByClassName('editorPanel');
        let rootElement;
        if (elements && elements.length) {
            rootElement = elements[0];
        }

        if (!DesignerBuilder) {
            return;
        }

        this.addServiceToDevkit();
        const designerHost = this.addServiceToUI();

        const childComponents = domJson.module.components.slice(1);
        const rootComponent = domJson.module.components[0];
        const designerSchema = {
            contents: [rootComponent]
        };
        this.designBuilder = new DesignerBuilder(rootElement, designerSchema, childComponents, AllComponents, designerHost);
        this.designBuilder.instance.ready.then(() => {
            this.onBuilderReady();

            // 加载控件工具箱
            this.controlBox.getDisplayedControls();

            // this.isBuilderReady = true;
            // 设计器渲染完毕，开始监听DOM变更
            window.suspendChangesOnForm = false;
        });

        this.designBuilder.instance.on('change', () => {
            this.onComponentChanged();
        });
        this.designBuilder.instance.on('removeComponent', () => {
            this.updatePropertyPanel(null);
            this.onComponentChanged();
        });
    }

    /**
     * 将UI中定义的控件相关服务添加到Devkit中
     */
    private addServiceToDevkit() {
        const designerHost = new DesignerHost();

        designerHost.addService('ControlService', this.controlService);
        designerHost.addService('ControlCreatorService', this.controlCreatorService);
        designerHost.addService('SchemaDOMMapping', SchemaDOMMapping);
        designerHost.addService('ControlEventPropertyIDList', ControlEventPropertyIDList);
        designerHost.addService('Injector', this.injector);
        this.designerHostSettingService.setDesignerHost(designerHost);

    }

    /**
     * 将服务添加到UI包中
     */
    private addServiceToUI(): IDesignerHost {
        const designerHost = new DesignerHost();
        designerHost.addService('DomService', this.domService);
        designerHost.addService('SchemaService', this.schemaService);
        designerHost.addService('DesignViewModelService', this.dgVMService);
        designerHost.addService('DragResolveService', this.dragResolveService);
        designerHost.addService('StateMachineService', this.stateMachineService);
        designerHost.addService('DataStatesService', this.dataStatesService);
        designerHost.addService('WebCmdService', this.webCmdService);
        designerHost.addService('EventEditorService', this.eventEditorService);
        designerHost.addService('ControlCreatorService', this.controlCreatorService);
        designerHost.addService('SchemaDOMMapping', SchemaDOMMapping);
        designerHost.addService('RefreshFormService', this.refreshFormService);
        designerHost.addService('FormBasicService', this.formBasicService);

        // 注入公共服务，用于控件中动态创建angular组件
        designerHost.addService('Injector', this.injector);
        designerHost.addService('ModalService', this.modalService);
        designerHost.addService('MessagerService', this.msgService);
        designerHost.addService('ComponentFactoryResolver', this.componentFactoryResolver);
        return designerHost;
    }

    public onBuilderReady() {

        this.componentInstanceList = this.designBuilder.instance.getAllComponents();

        // 更新控件json映射
        this.domService.updateDomDgMap(this.componentInstanceList);

        // 重新挂载控件事件
        this.reAttachComponentEvent(this.componentInstanceList);

        // 监听容器尺寸变化
        this.registerResizeListenner();

        // 监听容器横向滚动条
        this.bindEditorPanelScrollListener();

        // 更新actions
        this.webCmdService.syncActions();
    }

    /**
     * 画布内控件发生变更
     */
    private onComponentChanged() {
        this.onBuilderReady();

        this.focusedComponentInstance = null;
        // 刷新控件树
        this.controlTree.refreshControlTree();

        // 刷新实体树（涉及到字段图标的颜色变化）
        this.schemaTree.refreshTreeData();
    }

    /**
     * 挂载控件点击事件
     * @param componentInstanceList 控件实例列表
     */
    private reAttachComponentEvent(componentInstanceList: any[]) {
        componentInstanceList.forEach((cmp: any) => {
            // 响应点击事件
            cmp.on('componentClicked', (data) => { this.onComponentClicked(data); });

            // 响应清除属性面板事件，常用于控件被移除的场景
            cmp.on('clearPropertyPanel', (data) => { this.updatePropertyPanel(null); });

            // 响应组件内部触发的变更事件，常用于控件内部触发的新增、删除子控件的场景
            cmp.on('componentChanged', (data) => { this.onComponentChanged(); });
        });
    }

    /**
     * 监听可视化区域的控件点击事件
     * @param controlComponent 选中的组件实例
     */
    private onComponentClicked(data: any) {
        if (!data || !data.length) {
            return;
        }
        const { e, componentInstance, needUpdatePropertyPanel } = data[0];
        if (!componentInstance) {
            return;
        }

        // 触发选中控件树节点。直接点击控件时e有值；点击控件树节点时e为undefined
        if (e) {
            this.controlTree.triggerTreeFocus(componentInstance.component.id);
        }

        // 触发更新属性面板(TODO 属性的收集逻辑在某些场景下会执行两遍)
        if (!this.focusedComponentInstance || componentInstance.id !== this.focusedComponentInstance.id || needUpdatePropertyPanel) {
            this.updatePropertyPanel(componentInstance);
        }

        // 记录选中的控件实例
        this.focusedComponentInstance = componentInstance;
    }

    /**
     * 触发更新属性面板
     */
    updatePropertyPanel(componentInstance: any) {
        window.suspendChangesOnForm = true;
        if (!componentInstance || !componentInstance.component) {
            this.propertyConfig = [];
            this.propertyData = {};

            window.suspendChangesOnForm = false;
            return;
        }

        if (componentInstance.getPropertyConfig) {
            this.propertyConfig = componentInstance.getPropertyConfig() || [];
        } else {
            this.propertyConfig = [];
        }
        this.propertyData = componentInstance.component;

        window.suspendChangesOnForm = false;
    }

    /**
     * 变更控件树节点
     * @param node 选中的树节点
     */
    public changeControlTreeNode(data: { treeNode: ControlTreeNode, dependentTreeNode?: ControlTreeNode, outsideNodeId?: string }) {

        const node = data.treeNode;
        if (!node) {
            this.updatePropertyPanel(null);
            return;
        }
        const { dependentTreeNode } = data;
        const { outsideNodeId } = data;
        if (outsideNodeId) {
            this.clickControlNode(node, dependentTreeNode, outsideNodeId);
            return;
        }
        switch (node.type) {
            // 表单控件节点
            case ControlTreeNodeType.Control:
            case ControlTreeNodeType.Component: {
                if (!this.updateDOMByMonacoCode()) {
                    return;
                }
                this.clickControlNode(node, dependentTreeNode);
                break;
            }
            // 顶层frame节点
            case ControlTreeNodeType.Frame: {
                if (!this.updateDOMByMonacoCode()) {
                    return;
                }
                this.clickFrameTreeNode(node);
                break;
            }
        }
    }

    /**
     * 控件树单击组件节点或控件节点
     */
    private clickControlNode(node: ControlTreeNode, dependentTreeNode?: ControlTreeNode, outsideNodeId?: string) {
        // 场景1：选择控件树上没有的控件
        if (outsideNodeId) {
            const componentInstance = this.componentInstanceList.find(instance => instance.id === outsideNodeId);
            if (componentInstance) {
                componentInstance.triggerComponentClick();
                this.updateMonacoCode();
            }
            return;
        }
        // 场景2：有依赖关系的节点，触发依赖节点的点击事件
        if (dependentTreeNode) {
            const componentInstance = this.componentInstanceList.find(instance => instance.id === dependentTreeNode.data.id);
            if (componentInstance && componentInstance.triggerComponentInsideClick) {
                componentInstance.triggerComponentInsideClick(node);
            }
        } else {
            // 场景3：获取节点对应的控件实例，并触发点击事件，从而显示属性面板
            const focusedComponentInstance = this.componentInstanceList.find(instance => instance.id === node.data.id);
            if (focusedComponentInstance) {
                focusedComponentInstance.triggerComponentClick();
            }
        }

        this.updateMonacoCode();
    }

    /**
     * 点击控件树顶层表单frame节点
     */
    private clickFrameTreeNode(node: ControlTreeNode) {
        window.suspendChangesOnForm = true;

        this.focusedComponentInstance = null;

        // 触发显示属性面板
        const frameProp = new FrameProp(this.injector);
        const customPropConfig = frameProp.getPropConfig(this.domJson);
        this.propertyConfig = customPropConfig;
        this.propertyData = this.domJson;

        // 移除可视化区域的选定边框
        const elements = document.getElementsByClassName('dgComponentSelected') as HTMLCollectionOf<BuilderHTMLElement>;
        if (elements && elements.length > 0) {
            Array.from(elements).forEach(element => {
                element.classList.remove('dgComponentSelected');
                if (element.componentInstance && element.componentInstance.afterComponentCancelClicked) {
                    element.componentInstance.afterComponentCancelClicked(null);
                }
            });

        }
        // 当前显示代码编辑器：获取最新DOM结构并进行格式化
        if (this.bottomTabActive === BOTTOM_TAB_TYPE.codeEditor) {
            this.updateMonacoCode();
        } else {
            window.suspendChangesOnForm = false;

        }

    }

    /**
     * 切换底部tab页
     */
    changeBottomBar(key) {

        // 重复点击无效
        if (this.bottomTabActive === key) {
            return;
        }
        switch (key) {
            // 切到代码编辑器
            case BOTTOM_TAB_TYPE.codeEditor: {
                this.saveClassEditorCode();
                this.updateMonacoCode();
                break;
            }
            // 切到样式编辑器
            case BOTTOM_TAB_TYPE.classEditor: {
                if (!this.updateDOMByMonacoCode()) {
                    return;
                }
                break;
            }
            // 切到可视化设计器
            case BOTTOM_TAB_TYPE.formDesigner: {
                this.saveClassEditorCode();
                if (!this.updateDOMByMonacoCode()) {
                    return;
                }
                this.refreshFormAndTree();
            }
        }
        this.bottomTabActive = key;
    }

    /**
     * 刷新页面
     * @param targetComponentId 需要刷新的目标组件id，若不传，则刷新整个页面
     */
    private refreshFormAndTree(targetComponentId?: string) {

        // 组合ViewModel数据：schema field+VM changeset => dgViewModel
        this.dgVMService.assembleDesignViewModel();

        // 更新DOM结构和子组件（不可少）
        const childComponents = this.domJson.module.components.slice(1);
        const rootComponent = this.domJson.module.components[0];
        const designerSchema = {
            contents: [rootComponent]
        };
        this.designBuilder.updateChildComponents(designerSchema, childComponents);

        // 挂起变更
        window.suspendChangesOnForm = true;
        // 局部重绘
        if (targetComponentId) {
            const needToBeRefreshedCmp = this.componentInstanceList.find(c => c.id === targetComponentId);
            if (needToBeRefreshedCmp) {
                needToBeRefreshedCmp.rebuild().then(() => {
                    this.onComponentChanged();

                    window.suspendChangesOnForm = false;
                });
            }
        } else {
            // 整个页面重绘
            this.designBuilder.instance.rebuild().then(() => {
                this.onComponentChanged();

                // 更新拖拽容器中的实体树和控件树
                // this.schemaTree.updateTreeNodesInDragula();
                this.controlBox.updateCategoryPanelsInDragula();

                window.suspendChangesOnForm = false;

            });
        }

    }

    /**
     * 切换左侧标签页
     */
    public changeSideBarTabTo(panelCode: string) {
        this.leftTabActive = panelCode as any;

        // 默认切换回可视化设计器，不展示代码编辑器或者设置视图
        if (this.bottomTabActive !== BOTTOM_TAB_TYPE.formDesigner) {
            this.bottomTabActive = BOTTOM_TAB_TYPE.formDesigner;
        }
    }

    /**
     * 切换属性面板标签页
     * @param tabId 标签页id
     */
    public onSelectedPropertyTabChanged(tabId) {
        this.selectedPropertyTabId = tabId;
    }

    /**
     * 属性变更后事件
     * @param changeObject 变更集
     */
    public onPropertyChanged(changeObject: FormPropertyChangeObject) {

        this.controlPropertyChangedService.afterPropertyChanged(
            changeObject,
            this.propertyData,
            null,
            this.focusedComponentInstance);

        this.updateControlTreeAfterPropertyChanged(changeObject);
    }

    /**
     * 属性变更后事件
     * @param data 变更集
     */
    public onPropertyModalChanged(data) {

        const { changeObject, parameters } = data;
        this.controlPropertyChangedService.afterPropertyChanged(
            changeObject,
            this.propertyData,
            parameters,
            this.focusedComponentInstance);

        this.updateControlTreeAfterPropertyChanged(changeObject);

    }

    /**
     * 属性面板展示模式发生变化
     */
    public onPropertyPanelShowModelChange(event: any) {
        const { mode = ShowMode.panel, width = undefined } = event || {};
        if (mode === ShowMode.panel) {
            this.propertyPanelWidth = width;
            this.propertyPanelResizeable = true;
        } else if (mode === ShowMode.sidebar) {
            this.propertyPanelWidth = width;
            this.propertyPanelResizeable = false;
        }
        this.cd.detectChanges();
    }

    /**
     * 刷新控件树
     * @param changeObject 变更集
     */
    private updateControlTreeAfterPropertyChanged(changeObject: FormPropertyChangeObject) {
        // 控件树整体刷新
        if (changeObject.needRefreshControlTree) {
            this.controlTree.refreshControlTree();
        }

        // 更新控件树节点名称
        if (changeObject.needUpdateControlTreeNodeName) {
            let shownName = changeObject.propertyValue && changeObject.propertyValue.trim();

            if (!changeObject.propertyValue) {
                shownName = (DgControl[this.propertyData.type] && DgControl[this.propertyData.type].name) || this.propertyData.id;
            }
            this.controlTree.updateControlTreeNodeData(this.propertyData.id, { name: shownName });
        }
    }

    /**
     *  代码编辑器初始化后事件，用于格式化代码
     */
    onMonacoInit($event) {
        this.monacoEditor = $event.editor;
        this.formatMonacoCode();

        // 监听代码编辑器的文本变化
        // this.monacoEditor.onDidChangeModelContent(() => {
        //     if (!window.suspendChangesOnForm) {
        //         this.isMonacoEditorChanged = true;

        //         if (!window.isFormMetadataChanged) {
        //             if (gsp && gsp.ide && gsp.ide.setDesignerStatus) {
        //                 gsp.ide.setDesignerStatus(this.iFrameTabId, true);
        //             }
        //             window.isFormMetadataChanged = true;
        //         }

        //     }
        // });
    }

    private formatMonacoCode() {
        if (!this.monacoEditor) {
            return;
        }
        this.ngZone.runOutsideAngular(() => {
            // 挂起变更
            window.suspendChangesOnForm = true;
            setTimeout(() => {

                const action = this.monacoEditor.getAction('editor.action.formatDocument');
                if (action) {

                    action.run().then(() => {
                        // 格式化结束，恢复变更
                        window.suspendChangesOnForm = false;
                    });
                } else {
                    window.suspendChangesOnForm = false;
                }
            }, 200);
        });
    }

    /**
     * 若是当前显示自定义样式页签，需要先保存定义样式
     */
    private saveClassEditorCode() {
        if (this.bottomTabActive === BOTTOM_TAB_TYPE.classEditor && this.classEditorComponent) {
            this.classEditorComponent.saveClassEditor();
        }
    }

    /**
     * 更新代码编辑绑定数据
     */
    updateMonacoCode() {
        if (this.focusedComponentInstance) {
            this.monacoCode = JSON.stringify(this.focusedComponentInstance.component);
        } else {
            this.monacoCode = this.domJson ? JSON.stringify(this.domJson) : '';
        }

        this.formatMonacoCode();
    }

    /**
     * 根据代码编辑器修改后的数据，更新表单DOM JSON
     */
    updateDOMByMonacoCode() {
        if (this.bottomTabActive !== BOTTOM_TAB_TYPE.codeEditor) {
            return true;
        }
        // 内容未发生变更
        if (!this.isMonacoEditorChanged) {
            return true;
        }
        // 校验数据，若校验失败禁止切换视图
        if (!this.monacoCode || !this.isJsonString(this.monacoCode)) {
            this.msgService.warning('代码格式错误，请检查标红部分');
            return false;
        }

        const newDomJson = JSON.parse(this.monacoCode);

        // 修改控件domDgMap
        if (this.focusedComponentInstance && this.focusedComponentInstance.type !== ControlTreeNodeType.Frame) {
            const oldDomJson = this.domService.domDgMap.get(this.focusedComponentInstance.id);
            if (oldDomJson) {
                Object.assign(oldDomJson, newDomJson);
                this.updateChildContentsDgMap(newDomJson);
            }
        } else {
            Object.assign(this.domJson, newDomJson);
        }

        // 校验DOM中viewmodel和component是否一一对应。主要用于手动修改代码编辑器后，导致的编译失败问题
        const validationServ = new DomValidtionService(this.domService, this.webCmdService, this.msgService);
        if (!validationServ.checkComponentAndViewModelCanMatch(this.domJson)) {
            return false;
        }

        return true;
    }

    /**
     * 根据代码编辑器序列化值更新DOM结构：容器类节点赋值后更新所有子节点DOM结构
     */
    private updateChildContentsDgMap(newDomJson: any) {

        if (Object.keys(newDomJson).includes('contents')) {
            newDomJson.contents.forEach(co => {
                this.domService.domDgMap.set(co.id, co);
                this.updateChildContentsDgMap(co);
            });
        }
    }

    /**
     * 保存前准备，主要解决：
     * 1. 在代码编辑器视图中修改dom后直接点保存的场景。
     * 2、校验dom中有没有冗余或者无效的代码片段
     */
    prepareBeforeFormSaved() {
        if (this.bottomTabActive === BOTTOM_TAB_TYPE.codeEditor) {
            if (!this.updateDOMByMonacoCode()) {
                return;
            }

        }
        if (this.bottomTabActive === BOTTOM_TAB_TYPE.classEditor) {
            this.classEditorComponent.saveClassEditor();
        }
        const validationServ = new DomValidtionService(this.domService, this.webCmdService, this.msgService);
        return validationServ.checkDocumentValidBeforeSaved();
    }

    /**
     * 控件树展示右键菜单前事件：用于组装菜单数据
     * @param data 控件树右键行数据
     */
    beforeShowContextMenu = (rowNode: RowNode, parentRowNode: RowNode) => {
        if (!rowNode) {
            return;
        }
        const treeNode = rowNode.node as TreeNode;

        let showMenu = false;
        let menus = [];

        // 获取右键菜单对应的组件实例
        let menuFocusedComponentInstance;
        if (parentRowNode) {
            menuFocusedComponentInstance = this.componentInstanceList.find(instance => instance.id === parentRowNode.node.id);
        } else {
            menuFocusedComponentInstance = this.componentInstanceList.find(instance => instance.id === treeNode.id);
        }

        if (menuFocusedComponentInstance && menuFocusedComponentInstance.resolveContextMenuConfig) {
            menus = menuFocusedComponentInstance.resolveContextMenuConfig(rowNode, parentRowNode);
            if (menus && menus.length) {
                showMenu = true;
            }
        }

        return {
            show: showMenu,
            menus
        };
    };

    /**
     *  监听容器尺寸变化
     */
    private registerResizeListenner() {
        // 监听画布内部区域的尺寸变化
        this.ro = new ResizeObserver(() => {
            if (this._roTimer) {
                clearTimeout(this._roTimer);
            }

            this._roTimer = setTimeout(() => {
                this.setPositionOfBtnGroup();
            });
        });
        // 因为画布有最小宽度，可能会出现滚动条，所以需要监听editorDiv的尺寸变化
        this.ro.observe(this.elRef.nativeElement.querySelector('.editorDiv'));
    }

    /**
     * 计算选中控件的工具栏位置
     */
    private setPositionOfBtnGroup() {
        const selectDom = this.elRef.nativeElement.querySelector('.dgComponentSelected');
        if (!selectDom) {
            return;
        }
        // 可视化区域在隐藏状态下，不计算工具栏定位。
        const selectDomRect = selectDom.getBoundingClientRect();
        if (selectDomRect.width === 0 && selectDomRect.height === 0) {
            return;
        }
        // 计算工具栏定位
        const toolbar = selectDom.querySelector('.component-btn-group');
        if (toolbar) {
            const toolbarRect = toolbar.getBoundingClientRect();
            const divPanel = toolbar.querySelector('div');
            const divPanelRect = divPanel.getBoundingClientRect();
            if (divPanel) {
                divPanel.style.top = toolbarRect.top + 'px';

                divPanel.style.left = (toolbarRect.left - divPanelRect.width) + 'px';

            }
        }

    }

    /**
     * 监听可视化区域的横向滚动条
     */
    private bindEditorPanelScrollListener() {
        const editorPanelEle = this.elRef.nativeElement.querySelector('.editorDiv');

        editorPanelEle.addEventListener('scroll', (e) => {
            this.setPositionOfBtnGroup();
        });
    }

    /**
     * 从【模型】页签切换到【页面】页签时，模型中的命令、参数可能发生了变更，如果当前【页面】包括【交互面板】，则需要更新【交互面板】绑定的数据。
     */
    updatePropertyPanelAfterModelChanged() {
        // 当前有已选的控件实例
        if (!this.focusedComponentInstance) {
            return;
        }

        // 当前控件的属性面板中包括【交互面板】
        const categoryTabs = this.propertyPanelComponent.categoryTabs || [];
        if (categoryTabs.find(tab => tab.tabId === 'commands')) {
            this.updatePropertyPanel(this.focusedComponentInstance);
        }
    }

    /**
     * 判断字符串是否可以合法转换为json数据
     */
    private isJsonString(jsonStr: string) {
        try {
            JSON.parse(jsonStr);
        } catch (error) {
            return false;
        }
        return true;
    }
}
